/*
 * Copyright (c) 2023-2024 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.common.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.List;
import org.elsfs.cloud.api.validation.group.GroupValidation;
import org.elsfs.cloud.common.core.vo.R;
import org.elsfs.cloud.common.mybatis.co.EditStateCo;
import org.elsfs.cloud.common.mybatis.repository.IElsfsRepository;
import org.elsfs.cloud.common.mybatis.utils.DateQuery;
import org.elsfs.cloud.common.util.exception.NotSupportedException;
import org.elsfs.cloud.common.util.lang.CollectionUtils;
import org.elsfs.cloud.starter.excel.annotation.RequestExcel;
import org.elsfs.cloud.starter.excel.annotation.ResponseExcel;
import org.elsfs.cloud.starter.excel.vo.ErrorMessage;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * 默认的增删改查接口
 *
 * @author zeng
 * @param <E> 实体类型
 * @param <Q> 实体类型
 * @param <Add> 实体类型
 * @param <Edit> 实体类型
 * @param <ER> 继承自 IElsfsRepository 的实体类型
 * @param <ID> id 类型
 */
public class RepositoryCrudController<
    E, Q extends E, Add extends E, Edit extends E, ER extends IElsfsRepository<E, ID>, ID> {
  @SuppressWarnings("all")
  @Autowired
  protected ER repository;

  protected ControllerConfig getConfig() {
    return new ControllerConfig()
        .list(false)
        .page(true)
        .getById(true)
        .add(true)
        .edit(true)
        .editState(true)
        .removeById(true)
        .removeBatch(true)
        .exportExcel(true)
        .exportExcel(true)
        .logicPage(false);
  }

  @GetMapping("/page")
  @Operation(summary = "分页查询", description = "分页查询")
  public R<IPage<?>> page(@ParameterObject Q entity, @ParameterObject DateQuery<E> qry) {
    if (!getConfig().page()) {
      return R.error("不支持分页查询");
    }
    return R.success(repository.page(qry.toPage(), qry.query(entity)));
  }

  @Operation(summary = "查询列表", description = "查询列表")
  @GetMapping("/list")
  public R<List<E>> list(E entity) {
    if (!getConfig().list()) {
      return R.error("不支持查询列表");
    }
    return R.success(repository.list(Wrappers.query(entity)));
  }

  /**
   * 通过id查询数据源表
   *
   * @param id id
   * @return R
   */
  @GetMapping("/getById/{id}")
  @Operation(summary = "通过id查询", description = "通过id查询")
  public R<? extends E> getById(@PathVariable("id") String id) {
    if (!getConfig().getById()) {
      return R.error("不支持通过 id 获取数据");
    }
    return R.success(repository.getById(id));
  }

  @PutMapping("/editState")
  @Operation(summary = "修改状态", description = "修改状态")
  public R<Boolean> editState(@RequestBody @Validated EditStateCo co) {
    if (!getConfig().editState()) {
      return R.error("不支持修改状态");
    }
    return R.success(repository.editState(co));
  }

  @PostMapping("/add")
  @Operation(summary = "添加接口", description = "添加接口")
  public R<Boolean> add(@RequestBody @Validated(GroupValidation.Add.class) Add co) {
    if (!getConfig().add()) {
      return R.error("不支持添加数据");
    }
    check(co, false);
    return R.success(repository.save(co), "添加成功");
  }

  @PutMapping("/edit")
  @Operation(summary = "修改接口", description = "修改接口")
  public R<Boolean> edit(@RequestBody @Validated(GroupValidation.Edit.class) Edit co) {
    if (!getConfig().edit()) {
      return R.error("不支持修改数据");
    }
    check(co, true);
    return R.success(repository.updateById(co), "修改成功");
  }

  @DeleteMapping("/del/{id}")
  @Operation(summary = "根据id删除接口", description = "根据id删除接口")
  public R<Boolean> removeById(@PathVariable("id") @NotBlank(message = "删除的id不能为空") String id) {
    if (!getConfig().removeById()) {
      return R.error("不支持删除数据");
    }
    return R.success(repository.removeById(id), "删除成功");
  }

  @DeleteMapping("/del")
  @Operation(summary = "批量删除接口", description = "批量删除接口")
  public R<Boolean> removeBatchByIds(
      @RequestBody @NotNull(message = "删除的ids不能为空") @Size(min = 1, message = "至少选择1条")
          List<String> ids) {
    if (!getConfig().removeBatch()) {
      return R.error("不支持删除数据");
    }
    return R.success(repository.removeByIds(ids), "删除成功");
  }

  @SuppressWarnings("unchecked")
  @GetMapping("/exportXls")
  @ResponseExcel
  @Operation(summary = "导出xls", description = "导出xls")
  public List<E> exportXls(@ParameterObject E entity, @ParameterObject DateQuery<E> dateQuery) {
    if (!getConfig().exportExcel()) {
      throw new NotSupportedException("不支持导出数据");
    }
    var eleList = repository.list(dateQuery.query(entity));
    return eleList;
  }

  /**
   * 导入部门
   *
   * @param list 列表
   * @param bindingResult 错误信息
   * @return r
   */
  @PostMapping("importExcel")
  public R importExcel(
      @RequestExcel @NotNull(message = "数据不能为空") @Size(min = 1, message = "至少选择1条") List<E> list,
      BindingResult bindingResult) {
    if (!getConfig().importExcel()) {
      R.error("不支持导入数据");
    }
    List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
    if (CollectionUtils.isNotEmpty(errorMessageList)) {
      return R.error(errorMessageList);
    }
    repository.saveBatch(list);
    return R.success("导入成功");
  }

  /**
   * 新增 修改 校验
   *
   * @param entity 实体
   * @param isUpdate 是否更新
   */
  protected void check(E entity, boolean isUpdate) {}
}
